home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / win / tkWinEmbed.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  17.0 KB  |  600 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkWinEmbed.c --
  3.  *
  4.  *    This file contains platform specific procedures for Windows platforms
  5.  *    to provide basic operations needed for application embedding (where
  6.  *    one application can use as its main window an internal window from
  7.  *    another application).
  8.  *
  9.  * Copyright (c) 1996 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * SCCS: @(#) tkWinEmbed.c 1.19 97/08/11 09:49:01;
  15.  */
  16.  
  17. #include "tkWinInt.h"
  18.  
  19.  
  20. /*
  21.  * One of the following structures exists for each container in this
  22.  * application.  It keeps track of the container window and its
  23.  * associated embedded window.
  24.  */
  25.  
  26. typedef struct Container {
  27.     HWND parentHWnd;            /* Windows HWND to the parent window */
  28.     TkWindow *parentPtr;        /* Tk's information about the container,
  29.                      * or NULL if the container isn't
  30.                      * in this process. */
  31.     HWND embeddedHWnd;            /* Windows HWND to the embedded window */
  32.     TkWindow *embeddedPtr;        /* Tk's information about the embedded
  33.                      * window, or NULL if the
  34.                      * embedded application isn't in
  35.                      * this process. */
  36.     struct Container *nextPtr;        /* Next in list of all containers in
  37.                      * this process. */
  38. } Container;
  39.  
  40. static Container *firstContainerPtr = NULL;
  41.                     /* First in list of all containers
  42.                      * managed by this process.  */
  43.  
  44. static void        CleanupContainerList _ANSI_ARGS_((
  45.                     ClientData clientData));
  46. static void        ContainerEventProc _ANSI_ARGS_((ClientData clientData,
  47.                 XEvent *eventPtr));
  48. static void        EmbedGeometryRequest _ANSI_ARGS_((
  49.                     Container*containerPtr, int width, int height));
  50. static void        EmbedWindowDeleted _ANSI_ARGS_((HWND hwnd));
  51.  
  52. /*
  53.  *----------------------------------------------------------------------
  54.  *
  55.  * CleanupContainerList --
  56.  *
  57.  *    Finalizes the list of containers.
  58.  *
  59.  * Results:
  60.  *    None.
  61.  *
  62.  * Side effects:
  63.  *    Releases memory occupied by containers of embedded windows.
  64.  *
  65.  *----------------------------------------------------------------------
  66.  */
  67.  
  68.     /* ARGSUSED */
  69. static void
  70. CleanupContainerList(clientData)
  71.     ClientData clientData;
  72. {
  73.     Container *nextPtr;
  74.     
  75.     for (;
  76.         firstContainerPtr != (Container *) NULL;
  77.         firstContainerPtr = nextPtr) {
  78.         nextPtr = firstContainerPtr->nextPtr;
  79.         ckfree((char *) firstContainerPtr);
  80.     }
  81.     firstContainerPtr = (Container *) NULL;
  82. }
  83.  
  84. /*
  85.  *----------------------------------------------------------------------
  86.  *
  87.  * TkpTestembedCmd --
  88.  *
  89.  *    Test command for the embedding facility.
  90.  *
  91.  * Results:
  92.  *    Always returns TCL_OK.
  93.  *
  94.  * Side effects:
  95.  *    Currently it does not do anything.
  96.  *
  97.  *----------------------------------------------------------------------
  98.  */
  99.  
  100.     /* ARGSUSED */
  101. int
  102. TkpTestembedCmd(clientData, interp, argc, argv)
  103.     ClientData clientData;
  104.     Tcl_Interp *interp;
  105.     int argc;
  106.     char **argv;
  107. {
  108.     return TCL_OK;
  109. }
  110.  
  111. /*
  112.  *----------------------------------------------------------------------
  113.  *
  114.  * TkpUseWindow --
  115.  *
  116.  *    This procedure causes a Tk window to use a given Windows handle
  117.  *    for a window as its underlying window, rather than a new Windows
  118.  *    window being created automatically. It is invoked by an embedded
  119.  *    application to specify the window in which the application is
  120.  *    embedded.
  121.  *
  122.  * Results:
  123.  *    The return value is normally TCL_OK. If an error occurred (such as
  124.  *    if the argument does not identify a legal Windows window handle),
  125.  *    the return value is TCL_ERROR and an error message is left in the
  126.  *    interp->result if interp is not NULL.
  127.  *
  128.  * Side effects:
  129.  *    None.
  130.  *
  131.  *----------------------------------------------------------------------
  132.  */
  133.  
  134. int 
  135. TkpUseWindow(interp, tkwin, string)
  136.     Tcl_Interp *interp;        /* If not NULL, used for error reporting
  137.                  * if string is bogus. */
  138.     Tk_Window tkwin;        /* Tk window that does not yet have an
  139.                  * associated X window. */
  140.     char *string;        /* String identifying an X window to use
  141.                  * for tkwin;  must be an integer value. */
  142. {
  143.     TkWindow *winPtr = (TkWindow *) tkwin;
  144.     int id;
  145.     HWND hwnd;
  146.     Container *containerPtr;
  147.  
  148.     if (winPtr->window != None) {
  149.         panic("TkpUseWindow: Already assigned a window");
  150.     }
  151.  
  152.     if (Tcl_GetInt(interp, string, &id) != TCL_OK) {
  153.         return TCL_ERROR;
  154.     }
  155.     hwnd = (HWND) id;
  156.  
  157.     /*
  158.      * Check if the window is a valid handle. If it is invalid, return
  159.      * TCL_ERROR and potentially leave an error message in interp->result.
  160.      */
  161.  
  162.     if (!IsWindow(hwnd)) {
  163.         if (interp != (Tcl_Interp *) NULL) {
  164.             Tcl_AppendResult(interp, "window \"", string,
  165.                     "\" doesn't exist", (char *) NULL);
  166.         }
  167.         return TCL_ERROR;
  168.     }
  169.  
  170.     /*
  171.      * Store the parent window in the platform private data slot so
  172.      * TkWmMapWindow can use it when creating the wrapper window.
  173.      */
  174.  
  175.     winPtr->privatePtr = (struct TkWindowPrivate*) hwnd;
  176.  
  177.     /*
  178.      * If this is the first container, register an exit handler so that
  179.      * things will get cleaned up at finalization.
  180.      */
  181.  
  182.     if (firstContainerPtr == (Container *) NULL) {
  183.         Tcl_CreateExitHandler(CleanupContainerList, (ClientData) NULL);
  184.     }
  185.     
  186.     /*
  187.      * Save information about the container and the embedded window
  188.      * in a Container structure.  If there is already an existing
  189.      * Container structure, it means that both container and embedded
  190.      * app. are in the same process.
  191.      */
  192.  
  193.     for (containerPtr = firstContainerPtr; containerPtr != NULL;
  194.         containerPtr = containerPtr->nextPtr) {
  195.     if (containerPtr->parentHWnd == hwnd) {
  196.         winPtr->flags |= TK_BOTH_HALVES;
  197.         containerPtr->parentPtr->flags |= TK_BOTH_HALVES;
  198.         break;
  199.     }
  200.     }
  201.     if (containerPtr == NULL) {
  202.     containerPtr = (Container *) ckalloc(sizeof(Container));
  203.     containerPtr->parentPtr = NULL;
  204.     containerPtr->parentHWnd = hwnd;
  205.     containerPtr->nextPtr = firstContainerPtr;
  206.     firstContainerPtr = containerPtr;
  207.     }
  208.  
  209.     /*
  210.      * embeddedHWnd is not created yet. It will be created by TkWmMapWindow(),
  211.      * which will send a TK_ATTACHWINDOW to the container window.
  212.      * TkWinEmbeddedEventProc will process this message and set the embeddedHWnd
  213.      * variable
  214.      */
  215.  
  216.     containerPtr->embeddedPtr = winPtr;
  217.     containerPtr->embeddedHWnd = NULL;
  218.  
  219.     winPtr->flags |= TK_EMBEDDED;
  220.     winPtr->flags &= (~(TK_MAPPED));
  221.  
  222.     return TCL_OK;
  223. }
  224.  
  225. /*
  226.  *----------------------------------------------------------------------
  227.  *
  228.  * TkpMakeContainer --
  229.  *
  230.  *    This procedure is called to indicate that a particular window will
  231.  *    be a container for an embedded application. This changes certain
  232.  *    aspects of the window's behavior, such as whether it will receive
  233.  *    events anymore.
  234.  *
  235.  * Results:
  236.  *    None.
  237.  *
  238.  * Side effects:
  239.  *    None.
  240.  *
  241.  *----------------------------------------------------------------------
  242.  */
  243.  
  244. void
  245. TkpMakeContainer(tkwin)
  246.     Tk_Window tkwin;
  247. {
  248.     TkWindow *winPtr = (TkWindow *) tkwin;
  249.     Container *containerPtr;
  250.  
  251.     /*
  252.      * If this is the first container, register an exit handler so that
  253.      * things will get cleaned up at finalization.
  254.      */
  255.  
  256.     if (firstContainerPtr == (Container *) NULL) {
  257.         Tcl_CreateExitHandler(CleanupContainerList, (ClientData) NULL);
  258.     }
  259.     
  260.     /*
  261.      * Register the window as a container so that, for example, we can
  262.      * find out later if the embedded app. is in the same process.
  263.      */
  264.  
  265.     Tk_MakeWindowExist(tkwin);
  266.     containerPtr = (Container *) ckalloc(sizeof(Container));
  267.     containerPtr->parentPtr = winPtr;
  268.     containerPtr->parentHWnd = Tk_GetHWND(Tk_WindowId(tkwin));
  269.     containerPtr->embeddedHWnd = NULL;
  270.     containerPtr->embeddedPtr = NULL;
  271.     containerPtr->nextPtr = firstContainerPtr;
  272.     firstContainerPtr = containerPtr;
  273.     winPtr->flags |= TK_CONTAINER;
  274.  
  275.     /*
  276.      * Unlike in tkUnixEmbed.c, we don't make any requests for events
  277.      * in the embedded window here.  Now we just allow the embedding
  278.      * of another TK application into TK windows. When the embedded
  279.      * window makes a request, that will be done by sending to the
  280.      * container window a WM_USER message, which will be intercepted
  281.      * by TkWinContainerProc.
  282.      *
  283.      * We need to get structure events of the container itself, though.
  284.      */
  285.  
  286.     Tk_CreateEventHandler(tkwin, StructureNotifyMask,
  287.     ContainerEventProc, (ClientData) containerPtr);
  288. }
  289.  
  290. /*
  291.  *----------------------------------------------------------------------
  292.  *
  293.  * TkWinEmbeddedEventProc --
  294.  *
  295.  *    This procedure is invoked by the Tk event dispatcher when
  296.  *    various useful events are received for the *children* of a
  297.  *    container window. It forwards relevant information, such as
  298.  *    geometry requests, from the events into the container's
  299.  *    application.
  300.  *
  301.  * Results:
  302.  *    None.
  303.  *
  304.  * Side effects:
  305.  *    Depends on the event.  For example, when ConfigureRequest events
  306.  *    occur, geometry information gets set for the container window.
  307.  *
  308.  *----------------------------------------------------------------------
  309.  */
  310.  
  311. LRESULT
  312. TkWinEmbeddedEventProc(hwnd, message, wParam, lParam)
  313.     HWND hwnd;
  314.     UINT message;
  315.     WPARAM wParam;
  316.     LPARAM lParam;
  317. {
  318.     Container *containerPtr;
  319.  
  320.     /*
  321.      * Find the Container structure associated with the parent window.
  322.      */
  323.  
  324.     for (containerPtr = firstContainerPtr;
  325.         containerPtr->parentHWnd != hwnd;
  326.         containerPtr = containerPtr->nextPtr) {
  327.     if (containerPtr == NULL) {
  328.         panic("TkWinContainerProc couldn't find Container record");
  329.     }
  330.     }
  331.  
  332.     switch (message) {
  333.       case TK_ATTACHWINDOW:
  334.     /* An embedded window (either from this application or from
  335.      * another application) is trying to attach to this container.
  336.      * We attach it only if this container is not yet containing any
  337.      * window.
  338.      */
  339.     if (containerPtr->embeddedHWnd == NULL) {
  340.         containerPtr->embeddedHWnd = (HWND)wParam;
  341.     } else {
  342.         return 0;
  343.     }
  344.  
  345.     break;
  346.       case TK_GEOMETRYREQ:
  347.     EmbedGeometryRequest(containerPtr, wParam, lParam);
  348.     break;
  349.     }
  350.     return 1;
  351. }
  352.  
  353. /*
  354.  *----------------------------------------------------------------------
  355.  *
  356.  * EmbedGeometryRequest --
  357.  *
  358.  *    This procedure is invoked when an embedded application requests
  359.  *    a particular size.  It processes the request (which may or may
  360.  *    not actually resize the window) and reflects the results back
  361.  *    to the embedded application.
  362.  *
  363.  * Results:
  364.  *    None.
  365.  *
  366.  * Side effects:
  367.  *    If we deny the child's size change request, a Configure event
  368.  *    is synthesized to let the child know that the size is the same
  369.  *    as it used to be.  Events get processed while we're waiting for
  370.  *    the geometry managers to do their thing.
  371.  *
  372.  *----------------------------------------------------------------------
  373.  */
  374.  
  375. void
  376. EmbedGeometryRequest(containerPtr, width, height)
  377.     Container *containerPtr;    /* Information about the container window. */
  378.     int width, height;        /* Size that the child has requested. */
  379. {
  380.     TkWindow * winPtr = containerPtr->parentPtr;
  381.     
  382.     /*
  383.      * Forward the requested size into our geometry management hierarchy
  384.      * via the container window.  We need to send a Configure event back
  385.      * to the embedded application even if we decide not to resize
  386.      * the window;  to make this happen, process all idle event handlers
  387.      * synchronously here (so that the geometry managers have had a
  388.      * chance to do whatever they want to do), and if the window's size
  389.      * didn't change then generate a configure event.
  390.      */
  391.     Tk_GeometryRequest((Tk_Window)winPtr, width, height);
  392.  
  393.     if (containerPtr->embeddedHWnd != NULL) {
  394.     while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {
  395.         /* Empty loop body. */
  396.     }
  397.  
  398.     SetWindowPos(containerPtr->embeddedHWnd, NULL,
  399.         0, 0, winPtr->changes.width, winPtr->changes.height, SWP_NOZORDER);
  400.     }
  401. }
  402.  
  403. /*
  404.  *----------------------------------------------------------------------
  405.  *
  406.  * ContainerEventProc --
  407.  *
  408.  *    This procedure is invoked by the Tk event dispatcher when
  409.  *    various useful events are received for the container window.
  410.  *
  411.  * Results:
  412.  *    None.
  413.  *
  414.  * Side effects:
  415.  *    Depends on the event.  For example, when ConfigureRequest events
  416.  *    occur, geometry information gets set for the container window.
  417.  *
  418.  *----------------------------------------------------------------------
  419.  */
  420.  
  421. static void
  422. ContainerEventProc(clientData, eventPtr)
  423.     ClientData clientData;        /* Token for container window. */
  424.     XEvent *eventPtr;            /* ResizeRequest event. */
  425. {
  426.     Container *containerPtr = (Container *)clientData;
  427.     Tk_Window tkwin = (Tk_Window)containerPtr->parentPtr;
  428.  
  429.     if (eventPtr->type == ConfigureNotify) {
  430.     if (containerPtr->embeddedPtr == NULL) {
  431.         return;
  432.     }
  433.     /* Resize the embedded window, if there is any */
  434.     if (containerPtr->embeddedHWnd) {
  435.         SetWindowPos(containerPtr->embeddedHWnd, NULL,
  436.             0, 0, Tk_Width(tkwin), Tk_Height(tkwin), SWP_NOZORDER);
  437.     }
  438.     } else if (eventPtr->type == DestroyNotify) {
  439.     /* The container is gone, delete the embedded window as well */
  440.     EmbedWindowDeleted(containerPtr->parentHWnd);
  441.     }
  442. }
  443.  
  444. /*
  445.  *----------------------------------------------------------------------
  446.  *
  447.  * TkpGetOtherWindow --
  448.  *
  449.  *    If both the container and embedded window are in the same
  450.  *    process, this procedure will return either one, given the other.
  451.  *
  452.  * Results:
  453.  *    If winPtr is a container, the return value is the token for the
  454.  *    embedded window, and vice versa.  If the "other" window isn't in
  455.  *    this process, NULL is returned.
  456.  *
  457.  * Side effects:
  458.  *    None.
  459.  *
  460.  *----------------------------------------------------------------------
  461.  */
  462.  
  463. TkWindow *
  464. TkpGetOtherWindow(winPtr)
  465.     TkWindow *winPtr;        /* Tk's structure for a container or
  466.                  * embedded window. */
  467. {
  468.     Container *containerPtr;
  469.  
  470.     for (containerPtr = firstContainerPtr; containerPtr != NULL;
  471.         containerPtr = containerPtr->nextPtr) {
  472.     if (containerPtr->embeddedPtr == winPtr) {
  473.         return containerPtr->parentPtr;
  474.     } else if (containerPtr->parentPtr == winPtr) {
  475.         return containerPtr->embeddedPtr;
  476.     }
  477.     }
  478.     panic("TkpGetOtherWindow couldn't find window");
  479.     return NULL;
  480. }
  481.  
  482. /*
  483.  *----------------------------------------------------------------------
  484.  *
  485.  * TkpClaimFocus --
  486.  *
  487.  *    This procedure is invoked when someone asks or the input focus
  488.  *    to be put on a window in an embedded application, but the
  489.  *    application doesn't currently have the focus.  It requests the
  490.  *    input focus from the container application.
  491.  *
  492.  * Results:
  493.  *    None.
  494.  *
  495.  * Side effects:
  496.  *    The input focus may change.
  497.  *
  498.  *----------------------------------------------------------------------
  499.  */
  500.  
  501. void
  502. TkpClaimFocus(topLevelPtr, force)
  503.     TkWindow *topLevelPtr;        /* Top-level window containing desired
  504.                      * focus window; should be embedded. */
  505.     int force;                /* One means that the container should
  506.                      * claim the focus if it doesn't
  507.                      * currently have it. */
  508. {
  509.     HWND hwnd = GetParent(Tk_GetHWND(topLevelPtr->window));
  510.     SendMessage(hwnd, TK_CLAIMFOCUS, (WPARAM) force, 0);
  511. }
  512.  
  513. /*
  514.  *----------------------------------------------------------------------
  515.  *
  516.  * TkpRedirectKeyEvent --
  517.  *
  518.  *    This procedure is invoked when a key press or release event
  519.  *    arrives for an application that does not believe it owns the
  520.  *    input focus.  This can happen because of embedding; for example,
  521.  *    X can send an event to an embedded application when the real
  522.  *    focus window is in the container application and is an ancestor
  523.  *    of the container.  This procedure's job is to forward the event
  524.  *    back to the application where it really belongs.
  525.  *
  526.  * Results:
  527.  *    None.
  528.  *
  529.  * Side effects:
  530.  *    The event may get sent to a different application.
  531.  *
  532.  *----------------------------------------------------------------------
  533.  */
  534.  
  535. void
  536. TkpRedirectKeyEvent(winPtr, eventPtr)
  537.     TkWindow *winPtr;        /* Window to which the event was originally
  538.                  * reported. */
  539.     XEvent *eventPtr;        /* X event to redirect (should be KeyPress
  540.                  * or KeyRelease). */
  541. {
  542.     /* not implemented */
  543. }
  544.  
  545. /*
  546.  *----------------------------------------------------------------------
  547.  *
  548.  * EmbedWindowDeleted --
  549.  *
  550.  *    This procedure is invoked when a window involved in embedding
  551.  *    (as either the container or the embedded application) is
  552.  *    destroyed.  It cleans up the Container structure for the window.
  553.  *
  554.  * Results:
  555.  *    None.
  556.  *
  557.  * Side effects:
  558.  *    A Container structure may be freed.
  559.  *
  560.  *----------------------------------------------------------------------
  561.  */
  562.  
  563. static void
  564. EmbedWindowDeleted(hwnd)
  565.     HWND hwnd;            /* Handle to the window that was deleted. */
  566. {
  567.     Container *containerPtr, *prevPtr;
  568.  
  569.     /*
  570.      * Find the Container structure for this window work.  Delete the
  571.      * information about the embedded application and free the container's
  572.      * record.
  573.      */
  574.  
  575.     prevPtr = NULL;
  576.     containerPtr = firstContainerPtr;
  577.     while (1) {
  578.     if (containerPtr->embeddedHWnd == hwnd) {
  579.         containerPtr->embeddedHWnd = NULL;
  580.         containerPtr->embeddedPtr = NULL;
  581.         break;
  582.     }
  583.     if (containerPtr->parentHWnd == hwnd) {
  584.         containerPtr->parentPtr = NULL;
  585.         break;
  586.     }
  587.     prevPtr = containerPtr;
  588.     containerPtr = containerPtr->nextPtr;
  589.     }
  590.     if ((containerPtr->embeddedPtr == NULL)
  591.         && (containerPtr->parentPtr == NULL)) {
  592.     if (prevPtr == NULL) {
  593.         firstContainerPtr = containerPtr->nextPtr;
  594.     } else {
  595.         prevPtr->nextPtr = containerPtr->nextPtr;
  596.     }
  597.     ckfree((char *) containerPtr);
  598.     }
  599. }
  600.